﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Utilities;

namespace PK2
{
    internal class CompletionSource : ICompletionSource
    {
        private CompletionSourceProvider m_sourceProvider;
        private ITextBuffer m_textBuffer;
        private List<Completion> m_compList;

        public CompletionSource(CompletionSourceProvider sourceProvider, ITextBuffer textBuffer)
        {
            m_sourceProvider = sourceProvider;
            m_textBuffer = textBuffer;
        }

        void ICompletionSource.AugmentCompletionSession(ICompletionSession session, IList<CompletionSet> completionSets)
        {
            //var set = completionSets.Where(c => c.DisplayName == "All").SingleOrDefault();
            
            var currentSpan = Helper.IsInComment(session.TextView, m_sourceProvider.AggregatorService);

            if (!currentSpan.Item1) return;

            var cs = PKContext.Current.Controller.GetCompletionSet();
            
            m_compList = new List<Completion>();
            foreach (var item in cs.Items)
                m_compList.Add(new Completion(item.DisplayText, cs.LaunchToken + item.InsertionText, item.Description, null, null));

            completionSets.Add(new SpecialCompletionSet(
                cs.DisplayName,    //the non-localized title of the tab
                session,
                FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer), session),
                session.GetTriggerPoint(m_textBuffer),
                m_compList,
                cs.LaunchToken));
        }

        //The following method is used to find the current word from the position of the caret.
        private ITrackingSpan FindTokenSpanAtPosition(ITrackingPoint point, ICompletionSession session)
        {
            SnapshotPoint currentPoint = (session.TextView.Caret.Position.BufferPosition) - 1;
            //ITextStructureNavigator navigator = m_sourceProvider.NavigatorService.GetTextStructureNavigator(m_textBuffer);
            //TextExtent extent = navigator.GetExtentOfWord(currentPoint);
            Span span = new Span(currentPoint.Position, 1);
            return currentPoint.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeInclusive);
        }

        private bool m_isDisposed;
        public void Dispose()
        {
            if (!m_isDisposed)
            {
                GC.SuppressFinalize(this);
                m_isDisposed = true;
            }
        }
    }

    internal class SpecialCompletionSet: CompletionSet
    {
        private string _filterBufferText;
        private ITrackingSpan completionSpan;
        private ITrackingPoint startPoint;
        private ICompletionSession session;
        private List<Completion> _completions;
        private char launchToken;
        FilteredObservableCollection<Completion> _filteredCompletions;
        FilteredObservableCollection<Completion> _filteredCompletionBuilders;

        public SpecialCompletionSet(string name, ICompletionSession session, ITrackingSpan applicableTo, ITrackingPoint startPoint,  List<Completion> completionList, char launchToken)
            :base(name, name, applicableTo , completionList,  null)
        {
            
            this._completions = completionList;
            this.session = session;
            this.startPoint = startPoint;
            this.completionSpan = applicableTo;
            this.launchToken = launchToken;

            this._filteredCompletions = new FilteredObservableCollection<Completion>(this.WritableCompletions);
            this._filteredCompletionBuilders = new FilteredObservableCollection<Completion>(this.WritableCompletionBuilders);
            
        }

        private string getPrefix()
        {
            //var cSpan = session.TextView.Caret.ContainingTextViewLine.Snapshot.cre
            var prefix = completionSpan.GetText(completionSpan.TextBuffer.CurrentSnapshot);

            return prefix;
        }

        //public override void Filter()
        //{
        //    base.Filter(CompletionMatchType.MatchDisplayText, false);
        //}

        public override IList<Completion> Completions
        {
            get
            {
               return _filteredCompletions;
            }
        }

        public override IList<Completion> CompletionBuilders
        {
            get
            {
                return _filteredCompletionBuilders;
            }
        }

        public override void SelectBestMatch()
        {
            Completion completion;

            string prefix = getPrefix();


            var completions = (from c in Completions
                               where c.InsertionText.IndexOf(prefix, StringComparison.InvariantCultureIgnoreCase) >= 0
                               select c).ToList();


            if (completions.Count > 0)
            {
                completion = completions.First();
                SelectionStatus = new CompletionSelectionStatus(completion, completion.InsertionText.Contains(prefix), completions.Count == 1);
            }

        //    string prefix = getPrefix();

        //    // precise match to a completion builder
        //    Completion completion = CompletionBuilders.FirstOrDefault(c => c.DisplayText.CompareTo(prefix) == 0);

        //    // if none - precise match to a completion 
        //    if (completion == null)
        //        completion = Completions.FirstOrDefault(c => c.DisplayText.CompareTo(prefix) == 0);

        //    // if none - position the completion list
        //    if (completion == null)
        //        completion = Completions.FirstOrDefault(c => c.DisplayText.CompareTo(prefix) >= 0);

        //    if (completion != null)
        //        SelectionStatus = new CompletionSelectionStatus(completion,
        //            completion.DisplayText == prefix,
        //            true
        //            );
        }

         public override void Filter()
        {
            ITextSnapshot currentSnapshot = this.ApplicableTo.TextBuffer.CurrentSnapshot;
            this._filterBufferText = getPrefix();
            if (String.IsNullOrEmpty(this._filterBufferText))
            {
                this._filteredCompletions.StopFiltering();
                this._filteredCompletionBuilders.StopFiltering();
            }
            else
            {
                this._filteredCompletions.Filter(c => c.InsertionText.IndexOf(this._filterBufferText, StringComparison.InvariantCultureIgnoreCase) >= 0);
                this._filteredCompletionBuilders.Filter(c => c.InsertionText.IndexOf(this._filterBufferText, StringComparison.InvariantCultureIgnoreCase) >= 0);
            }
        }

        public char LaunchToken
        {
            get { return launchToken; }
        }

        
    }
}
